FE-1602: Restyle the Petrinaut architecture docs - #9527
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
97106d2 to
770ac44
Compare
Restate Starlight's palette and type scale as one flat monochrome system, so the chrome reads as a single surface divided by hairlines and colour is left to the things that carry meaning. Collapsing the left panel now animates: the pane hides with visibility rather than display, the content inset derives from the pane width, and every box sized from it transitions on one curve. A drag or a held arrow key already tracks its input, so the handle marks the gesture and the transitions stand aside.
The borders framing the header, the sidebar and the on-this-page column are gone, leaving the sidebar's depth guide as the only rule drawn in the chrome, where it says how deep a row sits in the tree. The search field and the compare chips now read by fill rather than by an outline, one step off the page background in either theme.
770ac44 to
6ca3ec5
Compare
Both rails and the collapse toggle sit at 70% until the pointer or keyboard focus reaches them, over 300ms, with the whole rail as the hover target. prefers-reduced-transparency turns the effect off. A 30px band under the header blurs and tints the content passing beneath it. backdrop-filter cannot ramp on its own, so the ramp is three stacked layers of increasing radius, each masked to a shorter band, and each filtering what the one beneath it produced. Blocks now sit 1.5rem apart with 2.25em above a section heading, and body copy is 17px: Starlight defines --sl-text-body but never applies it, so the size had to be set here.
The band ran both to 30px, which hid the blur: its strongest layers sit at the top, which is exactly where the tint is opaque. The tint keeps its 30px and the blur now runs to 60px, so below the tint there is a stretch where content is blurred and still visible. Radii go up with it, 4px to 16px.
The three layers now differ by height rather than by mask alone. All are anchored under the header and run to a different depth: 60px at 1px of blur, 40px at 2px, 20px at 4px. They overlap towards the header and thin out to one at the bottom, so the tallest and weakest is the layer that meets unblurred content. Each fades out over its own lower half, so a layer ending reads as a soft edge rather than a line across the page.
The band's construction moves to a shared class so the rail and the content column build it from one set of rules. The rail scrolls independently of the page, so its band keys off the pane's own scrollTop and appears only once rows have gone up behind the header. Shown unconditionally it would sit on the first row of an unscrolled rail and dim it for nothing.
Height and opacity both come off `--pnd-nav-progress`, which the header script writes from the rail's scrollTop, 0 to 1 over the first 60px. At rest the band has no height, so it stays off the first row of an unscrolled rail. Nothing eases it: the value already tracks the scroll frame by frame, and a transition would leave the band lagging the rows it covers. The ramp is now two layers rather than three, 60px at 1px of blur and 30px at 2px, in both places the band is used.
PR SummaryLow Risk Overview Diagram pipeline: Reviewed by Cursor Bugbot for commit e582f87. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved moderate issues affect accessibility, persistence behavior, content scope, and SVG processing coverage.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Restyles the Petrinaut architecture docs, animates sidebar behavior, adds Inter fonts, and enables theme-aware inline diagrams.
Changes:
- Introduces monochrome styling, updated typography, fades, and responsive animations.
- Improves sidebar resizing, persistence, and scroll effects.
- Adds themeable SVG diagrams and supporting documentation.
File summaries
| File | Description |
|---|---|
yarn.lock |
Resolves new Markdown and HAST dependencies. |
libs/@local/petrinaut-arch-docs/src/emit/d2.ts |
Adds themeable SVG processing. Moderate: Add focused tests for scoped-rule insertion and unchanged output without a D2 scope. |
libs/@local/petrinaut-arch-docs/src/cli.ts |
Supplies the font path during D2 rendering. |
libs/@local/petrinaut-arch-docs/README.md |
Documents diagram theming. Nit: Use an opaque host-background value for n7 to avoid lines crossing labels. |
libs/@local/petrinaut-arch-docs/fonts/OFL.txt |
Adds the Inter font license. |
libs/@local/petrinaut-arch-docs/content/diagrams/gpu-batch-lifecycle.d2 |
Moderate: Revert the semantic label edits or document and validate them as content changes. |
apps/petrinaut-docs/src/styles/chrome.css |
Implements the redesign and animations. Moderate: Raise idle opacity values to meet control and text contrast requirements. |
apps/petrinaut-docs/src/plugins/inline-diagrams.mjs |
Inlines generated SVG diagrams. |
apps/petrinaut-docs/src/components/SiteTitle.astro |
Adds fades and revised resize behavior. Moderate: Persist keyboard-resized width once on keyup or blur, not on every repeated keydown. |
apps/petrinaut-docs/src/components/Head.astro |
Emits and preloads Inter. |
apps/petrinaut-docs/README.md |
Documents styling, motion, diagrams, and fonts. |
apps/petrinaut-docs/package.json |
Adds Markdown-processing dependencies. |
apps/petrinaut-docs/astro.config.mjs |
Registers diagram inlining and Inter. |
Review details
- Files reviewed: 12/15 changed files
- Comments generated: 5
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
A held arrow key repeats about thirty times a second and each repeat wrote to localStorage, which writes synchronously. The width a keyboard gesture reaches is now kept in hand and written when the gesture ends on keyup or blur, the same as a drag already did.
The rails and the header controls rest behind an opacity, so what a reader sees is their colour composited against the page, not the colour written in the stylesheet. Starlight's gray-3 arrives at 3.6:1 that way where body text owes 4.5:1, and at 50% the toggle's icon is 2.3:1 against the 3:1 a control owes. The fade is kept exactly as designed and the colour underneath it is raised instead, to the greys whose composite clears each threshold. The theme select moves to the rails' opacity: it is the one header control carrying a visible label, and at 50% over a white page no colour reaches 4.5:1, pure black included. Measured on the page rather than computed from the tokens: worst of 107 sidebar rows and 6 table-of-contents rows, both themes, 4.93:1 dark and 5.09:1 light for text, 3.68:1 and 3.19:1 for the icon.
The theming hook matches a format d2 owns: the scope class it puts on a drawing, and the colours it wrote. A change to either would stop every host override silently, with the diagrams still rendering in the palette they were drawn in. Tests cover the scoping, the drawn colour standing as each fallback, markup without a scope passing through, and the mask channels being left alone, which is the failure that erased every connection line the first time. The README offered n7 as transparent. It is the drawing's paper and also fills the rects that knock connections out from behind their labels, so a transparent one leaves every label struck through.
The bands took their progress from a number the header script wrote on every scroll, so a page restored to a scroll position painted once without them and then with them. Measured against first contentful paint, that write lands 4ms late on an idle machine and 181ms late under a 6x CPU throttle, which is the flash: about eleven frames of a page whose bands arrive after the content. A scroll-driven animation resolves the same progress from layout, on the first frame, and takes the scroll listeners with it. The rail's bands reach its scroller through a named timeline, since they are drawn in the header rather than inside the rail, and the foot band runs reversed over the last stretch of the scroll, which is how what is left below the fold falls out of a timeline that only counts distance travelled. Its ResizeObserver goes too: an opened group changes the timeline's own extent. Firefox has shipped neither half, so the script stays as the fallback there, gated on the same condition the stylesheet tests. The ramp is a CSS token now, read by the script rather than repeated in it.
…'s inset The rail now rests at 52.5% and the collapse button at 37.5%, three quarters of what each sat at. The right-hand panel and the theme select are left where they were. This costs contrast, and no colour buys it back: composited, rail text lands at 3.1:1 against the 4.5:1 body text owes, and the button's icon at 2.5:1 dark and 2.3:1 light against 3:1. At 52.5% over a white page even pure black reaches only 4.35:1, and at 37.5% only 2.6:1, so the lever is the resting opacity rather than the grey. Both still come to full strength on hover and on keyboard focus, and reduced-transparency turns the fade off. The note in the stylesheet records the measured figures rather than the ones it used to claim. The button also moves 4px left, to sit 16px from the viewport's left edge, which is what the 64px header leaves above a 32px button. The title wrapper clips its overflow, so it is extended by the same 4px and given it back as padding: the clip boundary travels with the button and the logo beside it does not move.
Lightning CSS rewrote the bands' rules as `animation: linear both pnd-fade-grow scroll(root)`. A timeline is not accepted in the `animation` shorthand — it was taken out while the spec settled — so the declaration was invalid and `animation-name` computed to `none`. Every built page therefore had no fade bands at all, and nothing said so: the dev server does not minify, so it kept working, and the header script had already stood down because the browser does support the CSS path. Only the published site was affected. The docs app minifies CSS with esbuild instead, which leaves the rules alone. `scripts/check-built-css.mjs` then reads the built stylesheets and fails the build on the shape that caused this, on a missing `animation-timeline`, and on a missing `@property` registration, so a build that draws no bands cannot be published quietly. Checked against the production preview: the band is 60px with the animation attached, where before the fix it was 0px.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 077f05c. Configure here.
Splitting `--pnd-rail-idle-opacity` out so the rail could rest lower than the right-hand panel left it out of the `prefers-reduced-transparency` rule, which still lifted only the two tokens that existed before. Every other piece of chrome went to full strength and the rail stayed at 52.5%, so the preference missed the one element that recedes furthest, and at that opacity its text is the 3.1:1 the stylesheet already records. Nothing tied a new token to that rule, so the built-CSS check now ties them: it collects every `--pnd-*-idle-opacity` declared and fails on any the rule does not lift. Run against the branch before the fix it named `--pnd-rail-idle-opacity` on its own. Measured with the media feature emulated: rail, right panel, toggle and theme select all resolve to 1 with the preference set, and to 0.525, 0.7, 0.375 and 0.7 without it.

Important
Appearance, plus the diagram renderer. No change to the architecture model or to page content, beyond two overlapping edge labels shortened on one diagram.
Summary
A new look for the architecture docs: Swiss, monochrome, and much quieter. One neutral ramp replaces Starlight's blues and greys, the chrome drops its dividers and steps back until it is pointed at, and everything that moves — the sidebar collapse, the resize, the bands under the header — now moves on one curve. Diagrams follow the page theme instead of staying white in the dark.
Before
9527-before.mp4
After
9527-after.mp4
Bands, script against scroll timeline
9527-fade-paths.mp4
Links
Changes
Appearance
prefers-reduced-transparencyanimationshorthand, where no browser accepts one, and the bands were dead in built output onlySidebar motion
visibility, so its rows travel with it and still leave the tab order at restprefers-reduced-motionResize handle
Diagrams
Test coverage
withThemeableColoursunit testslint:tscand the production buildHow to test